package com.lemon.cloud.author.oauth2.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

/**
 * @param
 * @author lemon
 * @description 默认情况下spring security的http配置 优于ResourceServerConfigurerAdapter的配置
 * @return
 * @date 2019-08-17 22:43
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    @Value("${spring.login.process.url:/loginProcess}")
    private String loginProcessUrl;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    protected UserDetailsService userDetailsService;

    /**
     * 密码验证处理器
     */
    @Autowired
    private AuthenticationProvider customerAuthenticationProvider;

    @Autowired
    private AuthenticationSuccessHandler selfAuthenticationSuccessHandler;

    @Autowired
    private AuthenticationFailureHandler selfAuthenticationFailureHandler;

    /**
     * @param
     * @return
     * @description 权限管理器
     * AuthorizationServerConfigurerAdapter认证中心需要的AuthenticationManager
     * @author lemon
     * @date 2019-08-17 22:46
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                // 目的是为了前端获取数据时获取到整个form-data的数据,提供验证器
                .authenticationProvider(this.customerAuthenticationProvider)
                // 配置登录user验证处理器 以及密码加密器  好让认证中心进行验证
                .userDetailsService(this.userDetailsService).passwordEncoder(this.passwordEncoder);
    }

    /**
     * @param
     * @return
     * @description 拦截所有请求, 使用httpBasic方式登陆
     * 会覆盖ResourceServerConfig中的配置
     * @author lemon
     * @date 2019-08-11 23:11
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // 跨域支持
                .cors()
                .and()
                // 定义哪些url需要被保护  哪些不需要保护
                .authorizeRequests()
                // 定义这两个链接不需要登录可访问
                .antMatchers("/", "/index", "/login", this.loginProcessUrl, "/login/form", "/css/**", "/oauth/**").permitAll()
                // 其他的都需要登录
                .anyRequest().authenticated()
                .and()
                // 如果未登录则跳转登录的页面   这儿可以控制登录成功和登录失败跳转的页面
                .formLogin()
                // TODO 指定值就会跳转失败
//                .loginPage("/custom/login")
                // 登录处理url
                .loginProcessingUrl(this.loginProcessUrl)
                // 定义用户与密码的parameter
                .usernameParameter("username").passwordParameter("password").permitAll()
                .successHandler(selfAuthenticationSuccessHandler)
                // 登录成功处理器
                .failureHandler(selfAuthenticationFailureHandler)
                .and()
                // 注销请求的路由为 "GET /logout"
                .logout().logoutUrl("/logout").permitAll()
                .invalidateHttpSession(true)
                .clearAuthentication(true)
                .and()
                .httpBasic()
                .and()
                // 防止跨站请求  spring security中默认开启
                .csrf().disable();
    }

    /**
     * @param
     * @return
     * @description 无法注入 使用 这种方式 授权中心管理器
     * @author lemon
     * @date 2019-08-11 23:12
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}